#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../include/NAry.h"
#include "../include/HashTable.h"
#include "../include/BST.h"
#include "../include/Trie.h"

extern int META_HEADER_START, FILE_DESCRIPTORS_START, FREE_LIST_START, BLOCKS_START;
extern fileSystemInfo fileSysInfo;
extern NAryNode *nAryRoot;

int add_file(char *destDirectory, char *fileName, char *dataFile)
{
	//Position of a Free Block...
	//Position of a Free Block..
	if(isVFSMounted==0) return 7;

	//if(fileSysInfo.isUnmounted==1) return 7;
	if(strcmp(destDirectory,"")==0 || strcmp(fileName,"")==0|| strcmp(dataFile,"")==0)
		return 0;
	char data[10240];
	int dataIndex=0;

	int freeBlock, freeBlockPosition;
 	int i;
	for(i=0; fileName[i]!='\0'; i++)
	//	if( !isalpha(fileName[i]) && !isdigit(fileName[i]) && !(fileName[i]=='/'))
		if(fileName[i]=='/')
			return 2;
	
	char destFile[100];
	strcpy(destFile, destDirectory);
	if(strcmp(destDirectory, "/")!=0)
		strcat(destFile, "/");
	strcat(destFile, fileName);
	BSTNode *bstNode = search_bst_node(destFile);
	if(bstNode != NULL)
		return 3;

	if(fileSysInfo.usedFileDescriptors == fileSysInfo.maxFileDescriptors)
		return 4;
	FILE *fp = fopen(dataFile, "rb");
	//FILE *fp2; //= fopen("/home/sriram/Desktop/img2.gif", "wb+");
	if(fp==NULL)
		return 5;

	/*Creating the Directory if it doesn't exist*/
	char *p, *q, r[100];
	char dirname1[100];
	strcpy(dirname1, destDirectory);
	q = strtok(dirname1, "/");
	strcpy(r, "");
	while(q!=NULL) 
	{
		strcat(r, "/");
		strcat(r, q);
		BSTNode *bstNode = search_bst_node(r);	
		if(bstNode==NULL)
		{
			fileDescriptor fd;
			fd.block = -1;
			strcpy(fd.locationFullPath, r);
			strcpy(fd.fileName, q);
			strcpy(fd.fileType, "dir");
			
			NAryNode *directory = insertNAryNode(&fd);
			insert_bst_node(&BSTRoot, directory->fd.locationFullPath, directory);	
			insert_hash_item(directory->fd.fileName, directory);
			
			fileSysInfo.usedFileDescriptors++;

		}
		q = strtok(NULL, "/");
	}


	char ch;
	fseek(fp, 0, SEEK_SET);
	//fseek(fp2, 0, SEEK_SET);
	while( !feof(fp) && (dataIndex<1023))
	{
		fread(&ch, sizeof(char), 1, fp);
		//fwrite(&ch, sizeof(char), 1, fp2);
		data[dataIndex++] = ch;
	}
	while(!feof(fp) && dataIndex<1029)
	{
		fread(&ch, sizeof(char), 1, fp);
		dataIndex++;
	}
	if(dataIndex>=1024){
		fclose(fp);
		 return 6;
	}
	data[dataIndex] = '\0';
	fclose(fp);
	//FreeList -- Finding a free Block
	freeBlock = get_free_block();
	freeBlockPosition = BLOCKS_START + sizeof(block)*freeBlock;

	//FileDescriptor -- Add to N Ary Tree --	
	fileDescriptor f;
	strcpy(f.locationFullPath, destDirectory);
	f.fileSize = dataIndex;
	if(destDirectory[strlen(destDirectory)-1]!='/')
		strcat(f.locationFullPath, "/");
	strcat(f.locationFullPath, fileName);
	strcpy(f.fileName, fileName);
	f.block = freeBlock;
	strcpy(f.fileType, "fil");

	NAryNode *file = insertNAryNode(&f);
	insert_bst_node(&BSTRoot, f.locationFullPath, file);
	insert_hash_item(file->fd.fileName, file);
	fileSysInfo.usedFileDescriptors++;	

	//FreeBlock -- Writing into the free Block... Incrementing the FreeList
	fp = fopen(fileSysInfo.fileSystemLabel, "rb+");
	fseek(fp, freeBlockPosition, SEEK_SET);
	block b;
	//strcpy(b.data, data); Wont Work

	for(i=0; i<f.fileSize; i++)
		b.data[i] = data[i];
	fwrite( &b, sizeof(block), 1,fp);
	
	fileSysInfo.freeBlock++;
	fclose(fp);

	construct_bst_tree();
	construct_hash_table();
	bstNode = search_bst_node(destFile);
/*
	//Content Based Search...
	fp = fopen(dataFile, "r");
	fseek(fp, 0, SEEK_SET);
	char buffer[100];
	int bufferIndex=0;
	while( !feof(fp) )
	{
		//fread(&ch, sizeof(char), 1, fp);
		char ch;
		ch = getc(fp);
		if(ch==' ' || ch=='\n' || ch=='\0')
		{
			buffer[bufferIndex] = '\0';
			insert_trie_node(buffer, file);
			bufferIndex=0;
		}
		else
			buffer[bufferIndex++] = ch;
		
	}
	fclose(fp);
*/
	return -1;
}
int export_file(char *filePath, char *destPath)
{
	if(isVFSMounted==0) return 4;
	//if(fileSysInfo.isUnmounted==1) return 4;
	if(strcmp(filePath,"")==0 || strcmp(destPath,"")==0)
		return 0;
	block b;
	/*if(strcmp(filePath, "")==0)
		return 3;
	if(strcmp(filePath, "")==0)
		return 4;
	*/
	BSTNode *bstNode = search_bst_node(filePath);
	if(bstNode==NULL)
		return 1;
	FILE *fp;
	/*if(fp)
	{
		fclose(fp);
		return 5;
	}*/
	if(strcmp(bstNode->nAryNode->fd.fileType, "dir")==0)
		return 3;
	fp = fopen(destPath, "wb+");
	if(!fp)
		return 2;
	fclose(fp);

	NAryNode *nAryNode = bstNode->nAryNode;

	int blockno = nAryNode->fd.block;
	fp = fopen(fileSysInfo.fileSystemLabel, "rb");//
	fseek(fp, BLOCKS_START + (blockno)*sizeof(block), SEEK_SET);
	fread(&b, sizeof(block), 1, fp);
	fclose(fp);

		fp = fopen(destPath, "wb+");
		fseek(fp, 0, SEEK_SET);		

		int i;

		for(i=0; i<(nAryNode->fd.fileSize); i++)
			fwrite(&(b.data[i]), sizeof(char), 1, fp);
/*
		//fwrite(b.data, sizeof(char), (nAryNode->fd.fileSize), fp);
		//fwrite(&b, sizeof(block), 1, fp);
		fclose(fp);
*/		
		fclose(fp);
		return -1;
}

int list_file(char *filePath, char *destPath)
{
	if(isVFSMounted==0) return 4;	
	//if(fileSysInfo.isUnmounted==1) return 4;
	if(strcmp(filePath,"")==0 || strcmp(destPath,"")==0)
		return 0;
	block b;
	BSTNode *bstNode = search_bst_node(filePath);
	if(bstNode==NULL)
		return 1;
	FILE *fp1 = fopen(destPath, "w+");
	if(fp1==NULL)
		return 3;
	fclose(fp1);
	char *position = strstr(bstNode->nAryNode->fd.fileName, ".txt");
	if(position==NULL)
		return 2;
	if(strcmp(position, ".txt")!=0)	//if .txt1
		return 2;

	NAryNode *nAryNode = bstNode->nAryNode;
	int blockno = nAryNode->fd.block;
	FILE *fp = fopen(fileSysInfo.fileSystemLabel, "rb");//		
	fseek(fp, BLOCKS_START + (blockno)*sizeof(block), SEEK_SET);
	fread(&b, sizeof(block), 1, fp);
	fclose(fp);
	
	fp = fopen(destPath, "w+");
	int i;
	fprintf(fp, "%s", b.data);
	fclose(fp);
	return -1;
}

int delete_file(char *fileName)
{
	if(isVFSMounted==0) return 2;	
	//if(fileSysInfo.isUnmounted==1) return 2;
	if(strcmp(fileName,"")==0)
		return 0;
	BSTNode *bstNode = search_bst_node(fileName);
	if(bstNode==NULL)
		return 1;
	if(strcmp(bstNode->nAryNode->fd.fileType, "dir")==0)
		return 1;	
	int blockno = deleteNAryNode(fileName, "fil");
	fileSysInfo.usedFileDescriptors--;
	//Add a Free Block
	fileSysInfo.freeBlock--;
	int freeListBlockPosition = FREE_LIST_START + sizeof(int)*(fileSysInfo.freeBlock);
	FILE *fp = fopen(fileSysInfo.fileSystemLabel, "rb+");
	fseek(fp, freeListBlockPosition, SEEK_SET);
	fwrite(&(blockno), sizeof(int), 1, fp);
	fclose(fp);	
	construct_bst_tree();
	construct_hash_table();
	return -1;
}
int update_file(char *outputFile, char *dataFile)
{
	if(isVFSMounted==0) return 4;	
	//if(fileSysInfo.isUnmounted==1) return 4;
	if(strcmp(outputFile,"")==0 || strcmp(dataFile,"")==0)
		return 0;
	block b;
	char data[1024];
	int dataIndex=0;


	char ch;
	
	BSTNode *bstNode = search_bst_node(outputFile);
	if(bstNode==NULL)
		return 1;
	FILE *fp = fopen(dataFile, "rb");
	if(!fp)
		return 2;
	fseek(fp, 0, SEEK_SET);
	while( !feof(fp) && (dataIndex<1023) )
	{
		fread(&ch, sizeof(char), 1, fp);
		data[dataIndex++] = ch;
	}
	while( !feof(fp) && (dataIndex<1027) )
	{
		fread(&ch, sizeof(char), 1, fp);
		dataIndex++;
	}
	if(dataIndex>=1024){
		fclose(fp);		
		 return 3;
	}	fseek(fp, 0, SEEK_SET);
	data[dataIndex]='\0';
	fclose(fp);

	bstNode = search_bst_node(outputFile);
	NAryNode *nAryNode = bstNode->nAryNode;
	int blockno = nAryNode->fd.block;
	fp = fopen(fileSysInfo.fileSystemLabel, "rb+");
	fseek(fp, BLOCKS_START + (blockno)*sizeof(block), SEEK_SET);
	strcpy(b.data, data);		
	fwrite(&b, sizeof(block), 1, fp);
	fclose(fp);
	return -1;
}
int copy_file(char *sourceFile, char *destFile)
{	
	if(isVFSMounted==0) return 5;	
	//if(fileSysInfo.isUnmounted==1) return 5;
	if(strcmp(sourceFile,"")==0 || strcmp(destFile,"")==0)
		return 0;
	/*if(strcmp(sourceFile, "")==0)
		return 3;
	if(strcmp(destFile, "")==0)
		return 4;
	*/
	if(search_bst_node(sourceFile)==NULL)
		return 1;
	
	char *dest;
	char *file;

	//strcpy(dest,"");
	 dest=(char*)malloc(sizeof(char)*100);
	file = strrchr(destFile, '/');
	
	strncpy(dest, destFile,strlen(destFile)-strlen(file));
	file++;
	if(strcmp(dest, "")==0)
		strcpy(dest, "/");
	if(search_bst_node(dest)==NULL)
		return 2;
	
	BSTNode *temp = search_bst_node(sourceFile);
	NAryNode *nAryNode1 = temp->nAryNode;
	if(strcmp(nAryNode1->fd.fileType, "dir")==0)
		return 3;
	if(fileSysInfo.usedFileDescriptors == fileSysInfo.maxFileDescriptors)
		return 4;
	if(strcmp(destFile, sourceFile)==0)
		return -1;
	if(search_bst_node(destFile)!=NULL)
		delete_file(destFile);
	
	NAryNode *naryNode = copyNAryNode(sourceFile, dest, "fil");
	strcpy(naryNode->fd.fileName, file);
	strcpy(naryNode->fd.locationFullPath, destFile);
	construct_bst_tree();
	construct_hash_table();
	fileSysInfo.usedFileDescriptors++;
	return -1;
}

int move_file(char *sourceFile, char *destFile)
{
	if(isVFSMounted==0) return 6;	
	//if(fileSysInfo.isUnmounted==1) return 6;
	if(strcmp(sourceFile,"")==0 || strcmp(destFile,"")==0)
		return 0;
	/*if(strcmp(sourceFile, "")==0)
		return 3;
	if(strcmp(destFile, "")==0)
		return 4;
	*/
	BSTNode *bstNode = search_bst_node(sourceFile);
	if(bstNode == NULL || (strcmp(bstNode->nAryNode->fd.fileType, "dir")==0) )
		return 1;

	char *dest;
	char *file;

	//strcpy(dest,"");
	dest=(char*)malloc(sizeof(char)*100);
	file = strrchr(destFile, '/');
	
	strncpy(dest, destFile,strlen(destFile)-strlen(file));
	file++;
	if(strcmp(dest, "")==0)
		strcpy(dest, "/");
	if(search_bst_node(dest)==NULL)
		return 2;
	if(strcmp(destFile, sourceFile)==0)
		return -1;
	if(search_bst_node(destFile)!=NULL)
	{
			delete_file(destFile);	
	}
	NAryNode *naryNode = moveNAryNode(sourceFile, dest, "fil");
	//moveNAryNode(sourceFile, destFile, "fil");
	strcpy(naryNode->fd.fileName, file);
	strcpy(naryNode->fd.locationFullPath, destFile);
	construct_bst_tree();
	construct_hash_table();

	return -1;
}


int search_file(char *name, char *outputFile)
{
	if(isVFSMounted==0) return 2;
	//if(fileSysInfo.isUnmounted==1) return 2;
	if(strcmp(name,"")==0 || strcmp(outputFile,"")==0)
		return 0;
	HashTableNode *hashNode = search_hash_item(name);			
	FILE *fp = fopen(outputFile, "w+");	
	if(fp==NULL)
		return -1;
	while(hashNode!=NULL)
	{
		//strncmp(hashNode->fileName, name, strlen(name))==0
		int index=0, length;
		if( strlen(hashNode->fileName)>strlen(name) )
			length = strlen(name);
		else
			length = strlen(hashNode->fileName);
		if(strncmp(hashNode->fileName, name, length)==0)		
		{
			//printf("%s\n", hashNode->nAryNode->fd.locationFullPath);
			fprintf(fp, "%s\r\n", hashNode->nAryNode->fd.locationFullPath);	
		}
		else
			break;
		hashNode = hashNode->next;
	}
	fclose(fp);
	return -1;
}

int search_file_content(char *name, char *outputFile)
{
	//printf("Searching %s", name);
	FILE *fp = fopen(outputFile, "w+");
	if(fp==NULL)
		return -1;	
	Trie *trieNode = search_trie_node(name);	
	NAryNode *tempNAryNode = NULL;
	if(trieNode!=NULL)		
		tempNAryNode = trieNode->nAryNode;
	while(tempNAryNode!=NULL)
	{
		printf("\n");
		printf("%s\n", tempNAryNode->fd.locationFullPath);	
		fprintf(fp, "%s\n", tempNAryNode->fd.locationFullPath);
		tempNAryNode = tempNAryNode->next;
	}
	fclose(fp);
	return -1;
}
